package com.zhouyong.protocol;

import com.zhouyong.message.Message;
import com.zhouyong.util.Utils;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToMessageCodec;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.List;

/**
 * 自定义传输协议（例如redis/http之类的规范），结合序列化类一起使用
 *
 * @author Y5696
 * @date 2023/3/13 13:50
 */
@Slf4j
@Component
@ChannelHandler.Sharable
public class CustomizeProtocol extends MessageToMessageCodec<ByteBuf, Message> {

    /**
     * 编码
     *
     * @param ctx
     * @param msg
     * @param list
     * @throws Exception
     */
    @Override
    protected void encode(ChannelHandlerContext ctx, Message msg, List<Object> list) throws Exception {
        try {
            log.info("==========消息编码中==========");
            ByteBuf out = ctx.alloc().buffer();
            // 1. 4 字节的魔数
            out.writeBytes(new byte[]{1, 2, 3, 4});
            // 2. 1 字节的版本,
            out.writeByte(1);
            // 3. 1 字节的序列化方式 jdk 0 , json 1
            out.writeByte(Utils.getSerializerType().ordinal());
            // 4. 1 字节的指令类型
            out.writeByte(msg.getMessageType());
            // 5. 4 个字节
            out.writeInt(msg.getSequenceId());
            // 无意义，对齐填充
            out.writeByte(0xff);
            // 6. 获取内容的字节数组
            byte[] bytes = Utils.getSerializerType().serialize(msg);
            // 7. 长度
            out.writeInt(bytes.length);
            // 8. 写入内容
            out.writeBytes(bytes);
            list.add(out);
        } catch (Exception e) {
            log.error("编码出现异常, cause: {}", e);
        }
    }

    /**
     * 解码
     *
     * @param ctx
     * @param in
     * @param list
     * @throws Exception
     */
    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> list) throws Exception {
        try {
            log.info("==========消息解码中==========");
            int magicNum = in.readInt();
            byte version = in.readByte();
            byte serializerAlgorithm = in.readByte(); // 0 或 1
            byte messageType = in.readByte(); // 0,1,2...
            int sequenceId = in.readInt();
            in.readByte();
            int length = in.readInt();
            byte[] bytes = new byte[length];
            in.readBytes(bytes, 0, length);

            // 找到反序列化算法
            ObjectSerialEnum serialEnum = ObjectSerialEnum.values()[serializerAlgorithm];
            // 确定具体消息类型
            Class<? extends Message> messageClass = Message.getMessageClass(messageType);
            // 反序列化
            Message message = (Message) serialEnum.deserialize(messageClass, bytes);
            list.add(message);
        } catch (Exception e) {
            log.error("解码出现异常,cause: {}", e.getMessage());
        }
    }
}
